package com.idealighter.game.recharge.manager;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;

import com.idealighter.game.common.CommonMsgMgr;
import com.idealighter.game.core.assertions.HuohuaAssert;
import com.idealighter.game.core.assertions.IdeaAssert;
import com.idealighter.game.core.constant.Operator;
import com.idealighter.game.core.error.ErrorCode;
import com.idealighter.game.dictionary.dic.RechargeItemDic;
import com.idealighter.game.dictionary.domain.RechargeItemDomain;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMgr;
import com.idealighter.game.player.struct.Player;
import com.idealighter.game.recharge.constant.AliPayConstant;
import com.idealighter.game.recharge.constant.WeChatPayConstant;
import com.idealighter.game.recharge.convert.RechareWeChatPayResultDtoConvert;
import com.idealighter.game.recharge.dto.RechareAliPayResultDto;
import com.idealighter.game.recharge.dto.RechareApplePayResultDto;
import com.idealighter.game.recharge.dto.RechareWeChatPayResultDto;
import com.idealighter.game.recharge.message.ReqRechargePayMsg;
import com.idealighter.game.recharge.struct.ValidationResult;
import com.idealighter.game.server.db.datadb.constant.RechargeRecordStateConstant;
import com.idealighter.game.server.db.datadb.convert.RechargeRecordConvert;
import com.idealighter.game.server.db.datadb.dao.AppleInAppPayReceiptDataDao;
import com.idealighter.game.server.db.datadb.dao.RechargeRecordDao;
import com.idealighter.game.server.db.datadb.generate.domain.AppleInAppPayReceiptDataDomain;
import com.idealighter.game.server.db.datadb.generate.domain.RechargeRecordDomain;
import com.idealighter.utils.check.EmptyUtil;
import com.idealighter.utils.code.RandCodeUtil;
import com.idealighter.utils.crypto.MD5Utils;
import com.idealighter.utils.time.TimeUtil;
import com.idealighter.utils.wepay.core.Wepay;
import com.idealighter.utils.wepay.model.pay.AppPayResponse;
import com.idealighter.utils.wepay.model.pay.PayRequest;

import java.util.Date;
import java.util.List;

import org.mybatis.guice.transactional.Transactional;

@Singleton
public class RechargeMgr {
  @Inject
  private RechargeItemDic rechargeItemDic;
  @Inject
  private RechargeMsgMgr rechargeMsgMgr;
  @Inject
  private CommonMsgMgr commonMsgMgr;
  private RechargeRecordDao rechargeRecordDao;
  @Inject
  private Wepay wepay;
  @Inject
  private AlipayClient alipayClient;
  @Inject
  private PlayerMgr playerMgr;
  private AppleInAppPayReceiptDataDao appleInAppPayReceiptDataDao;


  private final boolean isSandbox;

  /**
   * 充值管理 . 构造函数.
   * 
   * @param rechargeRecordDao 充值dao.
   * @param appleInAppPayReceiptDataDao 苹果支付dao.
   * @param isSandbox 是否沙箱.
   */
  @Inject
  public RechargeMgr(RechargeRecordDao rechargeRecordDao,
      AppleInAppPayReceiptDataDao appleInAppPayReceiptDataDao,
      @Named("applePay.sandbox") boolean isSandbox) {
    this.isSandbox = isSandbox;
    this.rechargeRecordDao = rechargeRecordDao;
    this.appleInAppPayReceiptDataDao = appleInAppPayReceiptDataDao;
  }

  /**
   * 获取充值选项列表.
   * 
   * @param player 玩家.
   */
  public ResMessage rechargeItemList(Player player) {
    List<RechargeItemDomain> domains = rechargeItemDic.list();
    return rechargeMsgMgr.resRechargeItemsMsg(domains);
  }

  /**
   * 校验充值数据 .
   * 
   * @Title appleAppPayCheck.
   * @author houdongsheng
   * @date 2018年1月17日 下午5:24:27
   * @param player 玩家
   * @param receipt 充值数据
   * @return ResMessage
   */
  @Transactional
  public ResMessage appleAppPayCheck(Player player, String order, String receipt) {
    HuohuaAssert.isTrue(EmptyUtil.stringIsNotEmpty(receipt));

    String md5Check = MD5Utils.encode(receipt);
    List<AppleInAppPayReceiptDataDomain> list =
        appleInAppPayReceiptDataDao.findReceiptDateByMd5(md5Check);
    if (EmptyUtil.listIsNotEmpty(list)) {
      for (AppleInAppPayReceiptDataDomain item : list) {
        HuohuaAssert.isTrue(!item.getReceiptData().equals(receipt),
            ErrorCode.INTERNAL_SERVER_ERROR);
      }
    }
    // 沙盒环境
    // ValidationResult validate = AppleReceiptValidation.validateReciept(receipt, true);
    // 真实环境
    ValidationResult validate = AppleReceiptValidation.validateReciept(receipt, isSandbox);
    HuohuaAssert.isTrue(validate != null, ErrorCode.INTERNAL_SERVER_ERROR);

    String product = validate.getReceipt().getInApp().get(0).getProductId();

    // 填写相应的值
    String orderNo = order;
    RechargeRecordDomain recordDomain = rechargeRecordDao.selectRechargeRecordByOrderNo(orderNo);
    HuohuaAssert.isTrue(recordDomain != null, ErrorCode.INTERNAL_SERVER_ERROR);

    // 判断产品编号是否一致
    Integer itemId = recordDomain.getRechargeItemId();
    RechargeItemDomain rechargeItem = rechargeItemDic.get(itemId);
    HuohuaAssert.isTrue(rechargeItem.getApplePayItem().equals(product),
        ErrorCode.INTERNAL_SERVER_ERROR);
    int fen = recordDomain.getPrice();
    String outSideOrderNo = validate.getReceipt().getInApp().get(0).getTransactionId();

    if (recordDomain.getState().equals(RechargeRecordStateConstant.WAIT_PAY)) {
      IdeaAssert.isTrue(fen == recordDomain.getPrice());
      int count = rechargeRecordDao.changeState(recordDomain.getId(),
          RechargeRecordStateConstant.WAIT_PAY, RechargeRecordStateConstant.PAYED);
      HuohuaAssert.isTrue(count > 0, ErrorCode.INTERNAL_SERVER_ERROR);

      // 增加用户金币
      boolean pay = playerMgr.recharge(recordDomain.getPlayerId(), recordDomain.getTradeNo(),
          recordDomain.getPayType().toString(), "微信-app支付", recordDomain.getPrice(),
          recordDomain.getGold() + recordDomain.getSendGold(), outSideOrderNo);
      HuohuaAssert.isTrue(pay, ErrorCode.INTERNAL_SERVER_ERROR);

      AppleInAppPayReceiptDataDomain receiptDomain = new AppleInAppPayReceiptDataDomain();
      receiptDomain.setCreateTime(new Date());
      receiptDomain.setMd5Check(md5Check);
      receiptDomain.setReceiptData(receipt);
      count = appleInAppPayReceiptDataDao.insert(receiptDomain);
      HuohuaAssert.isTrue(count > 0, ErrorCode.INTERNAL_SERVER_ERROR);
    }
    return ResMessage.DEFAULT;
  }

  /**
   * 充值 .
   * 
   * @Title rechargePay.
   */
  @Transactional
  public ResMessage rechargePay(Player player, Integer itemId, ReqRechargePayMsg.PayType payType) {
    if (payType == null || itemId == null) {
      commonMsgMgr.sendErrorDlgMsg(player, ErrorCode.BAD_REQUEST, Operator.SYSTEM);
      HuohuaAssert.isTrue(false, ErrorCode.BAD_REQUEST);
    }
    RechargeItemDomain itemDomain = rechargeItemDic.get(itemId);
    if (itemDomain == null) {
      commonMsgMgr.sendErrorDlgMsg(player, ErrorCode.RECHARGE_ITEM_NOT_EXIST, Operator.SYSTEM);
      HuohuaAssert.isTrue(false, ErrorCode.RECHARGE_ITEM_NOT_EXIST);
    }

    String tradeNo = RandCodeUtil.generateTradeNo();
    String outsideNo = "";
    int price = itemDomain.getPrice();
    Byte state = RechargeRecordStateConstant.WAIT_PAY;

    RechargeRecordDomain record = RechargeRecordConvert.INSTANCE.newInstance(tradeNo, outsideNo,
        (byte) payType.getId(), player.getId(), itemDomain.getId(), itemDomain.getGold(),
        itemDomain.getSendGold(), price, TimeUtil.now(), null, state);
    int count = rechargeRecordDao.addRechargeRecord(record);
    if (count <= 0) {
      commonMsgMgr.sendErrorDlgMsg(player, ErrorCode.INTERNAL_SERVER_ERROR, Operator.SYSTEM);
      HuohuaAssert.isTrue(false, ErrorCode.INTERNAL_SERVER_ERROR);
    }

    Integer fen = price;
    Long expireInSecs = 10 * 60L;

    RechareAliPayResultDto aliPay = null;
    RechareWeChatPayResultDto weChatPay = null;
    RechareApplePayResultDto applePay = null;

    if (payType.equals(ReqRechargePayMsg.PayType.WE_CHAT_PAY)) {
      AppPayResponse appPayResponse = appPay(tradeNo, fen, expireInSecs);
      weChatPay = RechareWeChatPayResultDtoConvert.INSTANCE.newInstance(
          appPayResponse.getPrepayId(), appPayResponse.getPartnerId(), appPayResponse.getNonceStr(),
          appPayResponse.getPkg(), appPayResponse.getPaySign(), appPayResponse.getTimeStamp());
    } else if (payType.equals(ReqRechargePayMsg.PayType.ALI_PAY)) {
      AlipayTradeAppPayResponse response;
      try {
        response = aliAppPay(tradeNo, fen, expireInSecs);
        aliPay = new RechareAliPayResultDto();
        aliPay.setContent(response.getBody());
      } catch (AlipayApiException e) {
        e.printStackTrace();
        HuohuaAssert.isTrue(false, ErrorCode.INTERNAL_SERVER_ERROR);
      }
    } else if (payType.equals(ReqRechargePayMsg.PayType.APPLE_IN_APP_PAY)) {
      applePay = new RechareApplePayResultDto();
      applePay.setOrderNo(tradeNo);
    }

    // 发送充值信息
    return rechargeMsgMgr.sendRechargePay(payType.getId(), weChatPay, aliPay, applePay);
  }

  private AppPayResponse appPay(String orderNo, Integer fen, Long expireInSecs) {
    PayRequest request = new PayRequest();
    request.setBody("预交金");
    request.setOutTradeNo(orderNo);
    request.setTotalFee(fen);
    request.setClientId("127.0.0.1");
    String notifyUrl = WeChatPayConstant.NOTIFY_URL;
    request.setNotifyUrl(notifyUrl);
    long now = System.currentTimeMillis();
    long expire = now + expireInSecs * 1000;
    request.setTimeStart(TimeUtil.format("yyyyMMddHHmmss", now));
    request.setTimeExpire(TimeUtil.format("yyyyMMddHHmmss", expire));
    return wepay.pay().appPay(request);
  }

  private AlipayTradeAppPayResponse aliAppPay(String orderNo, Integer fen, Long expireInSecs)
      throws AlipayApiException {
    AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
    model.setBody("用户充值");
    model.setSubject("充值" + fen / 100);
    model.setOutTradeNo(orderNo);
    model.setTimeoutExpress(expireInSecs / 60 + "m"); // 多少分钟之内有效
    model.setTotalAmount("" + (fen * 1.0 / 100));
    model.setProductCode("QUICK_MSECURITY_PAY");

    AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
    request.setBizModel(model);
    request.setNotifyUrl(AliPayConstant.NOTIFY_URL);
    AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
    return response;
  }

  /**
   * 充值列表 .
   *
   * @author abin
   * @date 2018年5月23日 下午4:22:10
   * @param player 玩家.
   * @param lastRecordId 最后充值项.
   * @param pageSize 页大小.
   * @return 消息.
   */
  public ResMessage rechargeRecordList(Player player, Integer lastRecordId, Integer pageSize) {
    if (lastRecordId != null && lastRecordId <= 0) {
      lastRecordId = null;
    }
    List<RechargeRecordDomain> recordDomains =
        rechargeRecordDao.selectByPage(player.getId(), lastRecordId, pageSize);
    return rechargeMsgMgr.resRechargeList(recordDomains);
  }
}
